package com.luping.xiao.xiao.utils.Thread;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;

/**
 * 参数介绍：
 * corePoolSize 核心线程数，指保留的线程池大小（不超过maximumPoolSize值时，线程池中最多有corePoolSize 个线程工作）。
 * maximumPoolSize 指的是线程池的最大大小（线程池中最大有corePoolSize 个线程可运行）
 * keepAliveTime 指的是空闲线程结束的超时时间（当一个线程不工作时，过keepAliveTime 长时间将停止该线程）。
 * unit 是一个枚举，表示 keepAliveTime 的单位（有NANOSECONDS, MICROSECONDS,
 * MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS，7个可选值）。
 * workQueue 表示存放任务的队列（存放需要被线程池执行的线程队列）。
 * threadFactory - 执行程序创建新线程时使用的工厂。
 * handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
 */

@Configuration
public class CustomThreadFactory {


    private int corePoolSize = 1;
    private int maximumPoolSize = 10;
    private long keepAliveTime = 0;

    /**
     * 1、直接提交。工作队列的默认选项是 SynchronousQueue，它将任务直接提交给线程而不保持它们。
     * 在此，如果不存在可用于立即运行任务的线程，则试图把任务加入队列将失败，
     * 因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。
     * 直接提交通常要求无界 maximumPoolSizes， 以避免拒绝新提交的任务。
     * 当命令以超过队列所能处理的平均数连续到达时，此策略允许无界线程具有增长的可能性。
     **/
    @Bean("getSynchronousQueueExecutorService")
    public ExecutorService getSynchronousQueueExecutorService() {
        ThreadFactory namedThreadFactory = new BasicThreadFactory.Builder().namingPattern("syn-pool-%d").daemon(true).build();
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                keepAliveTime, TimeUnit.MILLISECONDS,
                new SynchronousQueue(), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
    }

    /**
     * 2、无界队列。使用无界队列（例如，不具有预定义容量的 LinkedBlockingQueue）将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。
     * 这样，创建的线程就不会超过 corePoolSize。（因此，maximumPoolSize的值也就无效了。）当每个任务完全独立于其他任务，即任务执行互不影响时，适合于使用无界队列；
     * 例如，在 Web页服务器中。这种排队可用于处理瞬态突发请求，当命令以超过队列所能处理的平均数连续到达时，此策略允许无界线程具有增长的可能性
     */
    @Bean("getLinkedBlockingQueueExecutorService")
    public ExecutorService getLinkedBlockingQueueExecutorService() {
        ThreadFactory namedThreadFactory = new BasicThreadFactory.Builder().namingPattern("link-pool-%d").daemon(true).build();
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                keepAliveTime, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue(), namedThreadFactory);
    }

    /**
     * 3、有界队列。当使用有限的 maximumPoolSizes时，有界队列（如 ArrayBlockingQueue）有助于防止资源耗尽，但是可能较难调整和控制。
     * 队列大小和最大池大小可能需要相互折衷：使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开 销，但是可能导致人工降低吞吐量。
     * 如果任务频繁阻塞（例如，如果它们是 I/O边界），则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小，CPU使用率较高，但是可能遇到不可接受的调度开销，这样也会降低吞吐量。
     * RejectedExecutionHandler：无法处理线程的handler
     * RejectedExecutionHandler接口提供了对于拒绝任务的处理的自定方法的机会。在ThreadPoolExecutor中已经默认包含了4中策略源代码如下
     * CallerRunsPolicy（直接运行run方法）：线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制，能够减缓新任务的提交速度。
     * 1.     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {  
     * 2.                 if (!e.isShutdown()) {  
     * 3.                     r.run();  
     * 4.                 }  
     * 5.             } 
     * 这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了，那么就直接使用调用线程本身run方法来执行。
     * AbortPolicy（抛异常）：处理程序遭到拒绝将抛出运行时RejectedExecutionException
     * 1.     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {  
     * 2.                 throw new RejectedExecutionException();  
     * 3.             } 
     *  这种策略直接抛出异常，丢弃任务。
     * DiscardPolicy（直接丢弃）：不能执行的任务将被删除
     * 1.     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {  
     * 2.             } 
     *  这种策略和AbortPolicy几乎一样，也是丢弃任务，只不过他不抛出异常。
     * DiscardOldestPolicy（抛弃最老的线程）：如果执行程序尚未关闭，则位于工作队列头部的任务将被删除，然后
     * 重试执行程序（如果再次失败，则重复此过程）
     * 1.     public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {  
     * 2.                 if (!e.isShutdown()) {  
     * 3.                     e.getQueue().poll();  
     * 4.                     e.execute(r);  
     * 5.                 }  
     *         } 
     * 该策略就稍微复杂一些，在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务，然后重新尝试运行该任务。这个策略需要适当小心。
     */
    @Bean("getArrayBlockingQueueExecutorService")
    public ExecutorService getArrayBlockingQueueExecutorService() {
        ThreadFactory namedThreadFactory = new BasicThreadFactory.Builder().namingPattern("array-pool-%d").daemon(true).build();
        return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                keepAliveTime, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue(100), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
    }

}
